package biz.datalk.industrialland.admin.component.upload;

import biz.datalk.commons.utils.IdProvider;
import biz.datalk.industrialland.common.exception.ApplicationException;
import biz.datalk.industrialland.common.exception.ServiceException;
import biz.datalk.industrialland.common.util.RedisUtil;
import biz.datalk.upload.autoconfigure.properties.UploadProperties;
import biz.datalk.upload.fdfs.DatalkFastDFSClient;
import biz.datalk.upload.model.FileObject;
import biz.datalk.upload.service.impl.UploadServiceImpl;
import biz.datalk.upload.util.CustomJsonUtil;
import biz.datalk.upload.util.FileUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.TypeUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.ConfigurableMimeFileTypeMap;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.lang.reflect.ParameterizedType;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author tarofang@163.com
 * @date 2021-11-02
 */
@Slf4j
public class CustomUploadServiceImpl extends UploadServiceImpl {

    private final RedisUtil redisUtil;
    private final UploadProperties uploadProperties;
    private final ConfigurableMimeFileTypeMap customConfigurableMimeFileTypeMap;

    public CustomUploadServiceImpl(
            UploadProperties uploadProperties, //
            ConfigurableMimeFileTypeMap customConfigurableMimeFileTypeMap, //
            RedisUtil redisUtil) {
        super(uploadProperties, customConfigurableMimeFileTypeMap);
        this.uploadProperties = uploadProperties;
        this.redisUtil = redisUtil;
        this.customConfigurableMimeFileTypeMap = customConfigurableMimeFileTypeMap;
    }

    @Override
    protected FileObject getObjectFromLocal(String objKey) {
        String localStoragePath = this.uploadProperties.getLocal().getLocalStoragePath();
        String prefix = this.uploadProperties.getLocal().getPrefixDir();
        // String filePath = localStoragePath + "/" + prefix + "/" + objKey;
        String filePath = localStoragePath + "/" + objKey;
        File file = new File(filePath);

        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }

        long fileSize = file.length();

        // 获取文件名
        String filename = "";
        try {
            String metadataFilePath = file.getAbsolutePath() + "_m";
            File metadataFile = new File(metadataFilePath);
            String json = IOUtils.toString(new FileInputStream(metadataFile), StandardCharsets.UTF_8);
            ParameterizedType parameterize = TypeUtils.parameterize(Map.class, String.class, String.class);
            Map<String, String> convertMap = CustomJsonUtil.json2JavaBean(json, parameterize);
            filename = MapUtils.getString(convertMap, METADATA_ORIG_NAME, "");
        } catch (Exception ex) {
        }


        String contentType;
        try {
            contentType = customConfigurableMimeFileTypeMap.getContentType(objKey);
            log.debug("search content type: {}", contentType);
        } catch (Exception ex) {
            contentType = "application/octet-stream";
        }
        contentType = StringUtils.isBlank(contentType) ? "application/octet-stream" : contentType;

        FileObject fileObject = new FileObject();
        fileObject.setBucketName(prefix);
        fileObject.setObjKey(objKey);
        fileObject.setInputStream(inputStream);
        fileObject.setFileSize(fileSize);
        fileObject.setContentType(contentType);
        fileObject.setFilename(filename);

        return fileObject;
    }

    @Override
    protected String getLocalSignedUrl(String objKey) {
        // 获取文件信息
        String localStoragePath = uploadProperties.getLocal().getLocalStoragePath();
        // String prefix = StringUtils.trimToEmpty(uploadProperties.getLocal().getPrefixDir());
        // String filePath = StringUtils.isNotBlank(prefix) //
        //         ? (localStoragePath + "/" + prefix + "/" + objKey) //
        //         : (localStoragePath + "/" + objKey);
        String filePath = localStoragePath + "/" + objKey;
        File file = new File(filePath);
        if (!file.isFile() || !file.exists()) {
            log.warn("Invalid file. [objkey={}, filePath={}]", objKey, file.getAbsolutePath());
            throw new ServiceException("文件不存在或已被删除");
        }

        return getFileSignUrl(objKey);
    }

    @Override
    protected String getFdfsSignedUrl(String objKey) {
        // 获取文件信息
        Map<String, Object> fileInfoMap = DatalkFastDFSClient.getInstance().getFileInfo(objKey);
        if (MapUtils.isEmpty(fileInfoMap)) {
            log.warn("Invalid file. [objkey={}]", objKey);
            throw new ServiceException("文件不存在或已被删除");
        }

        return getFileSignUrl(objKey);
    }

    private String getFileSignUrl(String objKey) {
        String uuidId = IdProvider.createUUIDId();
        String prefixUrl = uploadProperties.getSignedUrlPrefix();
        if (StringUtils.isBlank(prefixUrl)) {
            throw new ApplicationException("prefixUrl no config");
        }

        String cacheKey = "FILE_SIGNED_URL:" + uuidId;
        redisUtil.set(cacheKey, objKey, 10, TimeUnit.MINUTES);

        prefixUrl = StringUtils.trimToEmpty(prefixUrl);
        prefixUrl = FileUtil.removeTailSeparator(prefixUrl);
        String signedUrl = prefixUrl + "/" + uuidId;
        log.debug("[objKey={}, signedUrl={}]", objKey, signedUrl);
        return signedUrl;
    }

    @Value("${use_local_signed_url: false}")
    private boolean useLocalSignedUrl;

    @Override
    public String getSignedUrl(String objKey) {
        if (useLocalSignedUrl) {
            return this.getFileSignUrl(objKey);
        }
        return super.getSignedUrl(objKey);
    }
}
